package main

import (
	"errors"
	"fmt"
	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
	"gorm.io/gorm"
	"log"
	"studygorm/tools"
	"time"
)

type User struct {
	ID         int64
	Username   string `gorm:"column:username"`
	Password   string `gorm:"column:password"`
	CreateTime int64  `gorm:"column:createtime"`
}

func (u User) TableName() string {
	return "users"
}

func demo1() {
	user := User{
		Username:   "codebaoku",
		Password:   "123456",
		CreateTime: time.Now().Unix(),
	}
	db := tools.GetDB()
	var err error
	if err = db.Debug().Create(&user).Error; err != nil {
		fmt.Println("插入失败", err)
		return
	}
	user = User{}
	result := db.Debug().Where("username=?", "codebaoku").Find(&user)
	if errors.Is(result.Error, gorm.ErrRecordNotFound) {
		fmt.Println("找不到记录")
		return
	}
	fmt.Println(user.Username, user.Password)
	db.Debug().Model(&user).Where("username=?", "codebaoku").Update("password", "654321")
	fmt.Println("更新后：", user.Username, user.Password)
	db.Debug().Where("username=?", "codebaoku").Delete(&User{})
}

func demo2() {
	u := User{
		Username:   "codebaoku",
		Password:   "123456",
		CreateTime: time.Now().Unix(),
	}
	db := tools.GetDB()
	err := db.Create(&u).Error
	if err != nil {
		fmt.Println("插入失败", err)
	} else {
		fmt.Println("插入成功", u.ID, u.Username)
	}
}

type Food struct {
	Id         int
	Title      string
	Price      float32
	Stock      int
	Type       int
	CreateTime time.Time
}

func (f Food) TableName() string {
	return "foods"
}

func demo3() {
	user := User{}
	db := tools.GetDB()
	db.Debug().Take(&user)
	fmt.Println(user)

	db.Debug().First(&user)
	fmt.Println(&user)

	db.Debug().Last(&user)
	fmt.Println(&user)

	var users []User
	db.Debug().Find(&users)
	fmt.Println(&users)

	var names []string
	db.Debug().Model(&User{}).Pluck("username", &names)
	fmt.Println(names)

	err := db.Take(&user).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		fmt.Println("查询无数据")
	} else if err != nil {
		fmt.Println("查询失败")
	}

	user = User{}
	db.Debug().Where("id = ?", 6).Take(&user)
	fmt.Println(user)

	users = []User{}
	db.Debug().Where("id in (?)", []int{5, 6}).Find(&users)
	fmt.Println(users)

	users = []User{}
	db.Debug().Select([]string{"id", "username"}).Where("create_time >= ? and create_time <= ?", "2018-11-06 00:00:00", "2018-11-06 23:59:59").Find(&users)
	fmt.Println(users)

	users = []User{}
	db.Debug().Select("id,username").Where("username like ?", "%%").Find(&users)
	fmt.Println(users)

	var counts []int
	db.Debug().Model(&User{}).Select("count(*) cnt").Pluck("cnt", &counts)
	fmt.Println(counts)

	users = []User{}
	db.Debug().Where("username like ?", "%%").Order("id desc").Limit(5).Offset(0).Find(&users)
	fmt.Println(users)

	var cnt int64
	db.Debug().Model(&User{}).Count(&cnt)
	fmt.Println(cnt)

	var results []Result
	db.Debug().Model(User{}).Select("username,count(*) as total").Group("username").Having("username!=''").Scan(&results)
	fmt.Println(results)

	results = []Result{}
	sql := "select username,count(*) as total from users group by username having username!=''"
	db.Debug().Raw(sql).Scan(&results)
	fmt.Println(results)
}

type Result struct {
	Username string
	Total    int
}

func demoUpdate() {
	user := User{}
	db := tools.GetDB()
	db.Debug().Where("id=?", 5).Take(&user)
	fmt.Println(user)
	user.Username = "yangzp"
	db.Debug().Save(&user)
	db.Debug().Where("id=?", 5).Take(&user)
	fmt.Println(user)

	user = User{ID: 6}
	db.Debug().Model(&user).Update("username", "Bob")
	fmt.Println(user)

	db.Debug().Model(&User{}).Where("id=?", 6).Update("username", "Alice")
	var username string
	db.Debug().Model(&User{}).Select("username").Where("id=?", 6).Pluck("username", &username)
	fmt.Println(username)

	user = User{ID: 6}
	updateUser := User{
		Username: "Mike",
		Password: "123456",
	}
	db.Debug().Model(&user).Updates(&updateUser)

	db.Debug().Model(&User{}).Where("id=?", 6).Updates(&updateUser)

	data := make(map[string]interface{})
	data["username"] = "Kate"
	db.Debug().Model(&User{}).Where("id=?", 6).Updates(data)

	db.Debug().Model(&User{}).Where("id=?", 6).Update("createtime", gorm.Expr("createtime+1"))
}

func demoDelete() {
	user := User{}
	db := tools.GetDB()
	db.Debug().Where("id=?", 6).Take(&user)
	db.Debug().Delete(&user)

	db.Debug().Where("id=?", 6).Delete(&User{})
}

func demoTransaction() {
	db := tools.GetDB()
	db.Debug().Transaction(func(tx *gorm.DB) error {
		err := tx.Create(&User{
			Username:   "LongQiC",
			Password:   "123456",
			CreateTime: time.Now().Unix(),
		}).Error
		if err != nil {
			return err
		}
		return nil
	})
}

func GetEnvInfo() string {
	//viper.SetConfigFile("./config.yaml")
	viper.SetConfigName("config")
	viper.SetConfigType("yaml")
	viper.AddConfigPath("./")
	if err := viper.ReadInConfig(); err != nil {
		panic(err)
	}
	fmt.Println(viper.GetString("host"))
	return viper.GetString("host")
}

type Server struct {
	Host string `mapstructure:"host"`
	Port string `mapstructure:"port"`
}

func getServerInfo() {
	var server Server
	viper.SetConfigName("config")
	viper.SetConfigType("yaml")
	viper.AddConfigPath("./")
	if err := viper.ReadInConfig(); err != nil {
		panic(err)
	}
	if err := viper.Unmarshal(&server); err != nil {
		panic(err)
	}
	fmt.Println(server.Host, server.Port)
	viper.OnConfigChange(func(in fsnotify.Event) {
		if err := viper.ReadInConfig(); err != nil {
			panic(err)
		}
		if err := viper.Unmarshal(&server); err != nil {
			panic(err)
		}
		fmt.Println(server.Host, server.Port)
	})
	for {
		viper.WatchConfig()
	}
}

func sum(a, b int) int {
	return a + b
}

func Zh(f func(a, b int) int) func(a, b int) int {
	return func(a, b int) int {
		log.Printf("日志中间件，记录操作数：a:%d,b:%d\n", a, b)
		return f(a, b)
	}
}

type F func(func(a, b int)) int

func main() {
	addWithLogging := Zh(sum)
	addWithLogging(2, 3)
	//getServerInfo()
}
